// We also detect if a gap occurs in the received stream of characters
// That can be useful if multiple characters are sent in burst
// so that multiple characters can be treated as a "packet"

module AsyncReceiver(
  iClk, 
  iRx, 
  oRxReady, 
  oRxData, 
  oRxEop, 
  oRxIdle
);

input iClk, iRx;
output reg oRxReady = 0;      // one clock pulse when oRxData is valid
output reg [7:0] oRxData = 0;
output reg oRxEop = 0;        // one clock pulse, when no more data is received (oRxIdle is going high)
output oRxIdle;               // no data is being received

// -------------------- Parameters -------------------------------------------------
parameter FREQUENCY = 50000000; // 50MHz
parameter BAUD = 115200;
parameter BAUD8 = BAUD*8;
parameter BAUD8_GENERATOR_WIDTH = 16;
parameter BAUD8_GENERATOR_INC = ((BAUD8 << (BAUD8_GENERATOR_WIDTH - 7)) + (FREQUENCY >> 8)) / (FREQUENCY >> 7);

// -------------------- Inner registers and wires ----------------------------------
reg [BAUD8_GENERATOR_WIDTH:0] baud8Generator = 0;
wire baud8Tick = baud8Generator[BAUD8_GENERATOR_WIDTH];
reg [1:0] rxSyncInv = 0;
reg [1:0] rxCntInv = 0;
reg rxBitInv = 0;
reg [3:0] state = 0;
reg [3:0] bitSpacing = 0;
// "nextBit" controls when the data sampling occurs
// depending on how noisy the iRx is, different values might work better
// with a clean connection, values from 8 to 11 work
wire nextBit = (bitSpacing == 8);
reg rxDataError = 0;
reg [4:0] gapCount = 5'b11111;

// --------------------- assigns ----------------------------------------------------
assign oRxIdle = gapCount[4];

// --------------------- always blocks ----------------------------------------------
always @(posedge iClk) begin
  baud8Generator <= baud8Generator[BAUD8_GENERATOR_WIDTH-1:0] + BAUD8_GENERATOR_INC;
end

always @(posedge iClk) begin
  if(baud8Tick) begin
    rxSyncInv <= {rxSyncInv[0], ~iRx};
  end
end

always @(posedge iClk) begin
  if(baud8Tick) begin
    if( rxSyncInv[1] && rxCntInv!=2'b11) begin
      rxCntInv <= rxCntInv + 1;
    end
    else if(~rxSyncInv[1] && rxCntInv!=2'b00) begin
      rxCntInv <= rxCntInv - 1;
    end

    if(rxCntInv == 2'b00) begin 
      rxBitInv <= 0;
    end
    else if(rxCntInv == 2'b11) begin
      rxBitInv <= 1;
    end
  end
end

always @(posedge iClk) begin
  if(state==0) begin
    bitSpacing <= 0;
  end
  else if(baud8Tick) begin
    bitSpacing <= {bitSpacing[2:0] + 1} | {bitSpacing[3], 3'b000};
  end
end

always @(posedge iClk) begin
  if(baud8Tick)
    case(state)
      4'b0000: if(rxBitInv)state <= 4'b1000;  // start bit found?
      4'b1000: if(nextBit) state <= 4'b1001;  // bit 0
      4'b1001: if(nextBit) state <= 4'b1010;  // bit 1
      4'b1010: if(nextBit) state <= 4'b1011;  // bit 2
      4'b1011: if(nextBit) state <= 4'b1100;  // bit 3
      4'b1100: if(nextBit) state <= 4'b1101;  // bit 4
      4'b1101: if(nextBit) state <= 4'b1110;  // bit 5
      4'b1110: if(nextBit) state <= 4'b1111;  // bit 6
      4'b1111: if(nextBit) state <= 4'b0001;  // bit 7
      4'b0001: if(nextBit) state <= 4'b0000;  // stop bit
      default: state <= 4'b0000;
    endcase
end

always @(posedge iClk) begin
  if(baud8Tick && nextBit && state[3])begin
    oRxData <= {~rxBitInv, oRxData[7:1]};
  end
end

always @(posedge iClk) begin
  begin
    oRxReady <= (baud8Tick && nextBit && state==4'b0001 && ~rxBitInv);      // ready only if the stop bit is received
    rxDataError <= (baud8Tick && nextBit && state==4'b0001 &&  rxBitInv);   // error if the stop bit is not received
  end
end

always @(posedge iClk) begin
  if (state!=0) begin
    gapCount<=0;
  end
  else if(baud8Tick & ~gapCount[4]) begin
    gapCount <= gapCount + 1;
  end
end

always @(posedge iClk) begin
  oRxEop <= baud8Tick & (gapCount==15);
end

endmodule
